package com.example.validatestudy.demos.tread.deadlock;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @auther: 王振方
 * @date: 2024 05 06 14 25
 * @description:
 */
public class NoSafeTest {
    public static void main(String[] args) {
        Account zhangsan = new Account("张三",100);
        Account lisi = new Account("李四",100);
        Account wangwu = new Account("王五",100);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,Integer.MAX_VALUE,60, TimeUnit.SECONDS
                ,new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());
        executor.execute(()->zhangsan.noSafeTransfer(lisi,100));
        executor.execute(()->wangwu.noSafeTransfer(lisi ,100));
        executor.shutdown();
    }

    @AllArgsConstructor
    @Data
    static class Account {
        private String name;
        private Integer balance;

        /**
         * 不加双重锁的情况
         * 结论：只锁this将会出现线程安全问题，
         * 原因：
         *  操作两个账户（成员变量）余额，转账时却只锁了其中一个，只能保证if判断和this账户的查询操作是原子性的，
         *  但另一个账户to的余额查询和收款操作不是原子性的。
         * @param to
         * @param num
         */
        synchronized void noSafeTransfer(Account to, Integer num){
            if (this.getBalance() >= num && this.getBalance()>0) {
                this.setBalance(this.getBalance() - num);
                System.out.println(Thread.currentThread().getName()+"扣款完成，"+this.getName()+"余额："+this.getBalance());
                int toBalance = to.getBalance();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                to.setBalance(toBalance + num);
                System.out.println(Thread.currentThread().getName()+"转账完成，"+to.getName()+"余额："+to.getBalance());
            } else {
                System.out.println(this.getName() + "转账余额不足！");
            }
        }
    }
}

